package com.sms.client;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.sms.client.exception.SendSmsException;
import com.sms.client.request.ContentSms;
import com.sms.client.request.TemplateSms;
import com.sms.client.utils.AESUtils;
import com.sms.client.utils.SignUtils;

/**
 * @desc 短信发送实例
 * @author WuJiangWu
 * @date 2018年7月20日下午12:14:03
 */
public class SmsClient {
    
    private Logger logger = Logger.getLogger(SmsClient.class.getName());

    /** 短信发送的地址 */
    private String url;
    /** 应用ID */
    private String appId;
    /** AES加密密钥  */
    private String secretKey;
    /** 配置默认短信模板  */
    private String templateCode;
    /** psot请求的body是否加密  */
    private boolean isEncrypt = false;
    /** 是否调试模式（true为生产环境、false为调试模式不会调用实际发信通道） */
    private boolean isDebug = false;
    
	private static final Pattern RESULT_PATTERN = Pattern.compile("^\\s*\\{\\s*\"state\"\\s*:\\s*(\\d+)\\s*,\\s*\"message\"\\s*:\\s*\"([^\"]*)\"",
        Pattern.MULTILINE);
    private static final String charset = "0123456789";// 短信随机因子
	private static final int codelen = 6;
        
	/** 构造函数 */
    public SmsClient(String url, String appId, String secretKey) {
        this.url = url;
        this.appId = appId;
        this.secretKey = secretKey;
    }
	/** 构造函数 */
    public SmsClient(String url, String appId, String secretKey, String templateCode) {
        this.url = url;
        this.appId = appId;
        this.secretKey = secretKey;
        this.templateCode=templateCode;
    }
    /** 构造函数 */
    public SmsClient(String url, String appId, String secretKey, String templateCode, boolean isDebug) {
    	this.url = url;
    	this.appId = appId;
    	this.secretKey = secretKey;
    	this.templateCode = templateCode;
    	this.isDebug = isDebug;
    }
    
	/**
     * 通过内容发送短信
     * @param sms xx
     * @throws SendSmsException xx
     */
    public void sendSms(ContentSms sms) throws SendSmsException {
        if (sms == null || SignUtils.isEmpty(sms.getContent()) || SignUtils.isEmpty(sms.getMobile())) {
            throw new NullPointerException("参数mobile,content不能为null");
        }
        StringBuffer sb = new StringBuffer();
        sb.append("{");
        sb.append(getBaseParams());
        sb.append(",\"mobile\":"+sms.getMobile());
        sb.append(",\"content\":"+sms.getContent());
        sb.append(",\"fromUser\":"+sms.getFromUser());
        sb.append(",\"toUser:\":"+sms.getToUser());
        sb.append("}");
        //执行http请求
        executeRequest(sb.toString());
    }
    
    /**
     * 通过模板发送短信
     * @param sms xx
     * @throws SendSmsException xx
     */
    public void sendSms(TemplateSms sms) throws SendSmsException {
        if (sms == null || SignUtils.isEmpty(sms.getMobile()) || SignUtils.isEmpty(sms.getTemplateCode()) ) {
            throw new NullPointerException("参数mobile,templateCode不能为null");
        }
        StringBuffer sb = new StringBuffer();
        sb.append("{");
        sb.append(getBaseParams());
        sb.append(",\"mobile\":\""+sms.getMobile()+"\"");
        sb.append(",\"templateCode\":\""+sms.getTemplateCode()+"\"");
        sb.append(",\"fromUser\":\""+sms.getFromUser()+"\"");
        sb.append(",\"toUser\":\""+sms.getToUser()+"\"");
        //封装模板参数
        sb.append(",\"parameters\":{");
        String str = "";
        if (sms.getParameters() != null && sms.getParameters().size() > 0) {
            for (Map.Entry<String, String> entry : sms.getParameters().entrySet()) {
                str += ",\""+entry.getKey()+"\":\""+entry.getValue()+"\"";
            }
        }
        sb.append(str.substring(1));
        sb.append("}}");
        //执行http请求
        executeRequest(sb.toString());
    }
    
    /** 包装必要参数 */
    private String getBaseParams() {
    	StringBuffer content = new StringBuffer();
    	content.append("\"appId\":\""+appId+"\"");
    	content.append(",\"timestamp\":\""+String.valueOf(System.currentTimeMillis())+"\"");//发信时间戳
    	content.append(",\"isDebug\":\""+String.valueOf(isDebug)+"\"");
        return content.toString();//
    }
    
    /**
     * 执行http短信请求
     * @param params
     * @throws SendSmsException
     * @throws IOException 
     */
    private void executeRequest(String json) throws SendSmsException{
    	StringBuffer log = new StringBuffer();
    	log.append("===================SmsClinet-begin===========================\r\n");
    	log.append("  url = "+this.url);
    	try {
	    	URL url = new URL(this.url);// 创建连接  
	        HttpURLConnection connection = (HttpURLConnection) url.openConnection();  
	        connection.setDoOutput(true);
	        connection.setDoInput(true);
	        connection.setUseCaches(false);  
	        connection.setInstanceFollowRedirects(true);
	        connection.setRequestMethod("POST"); // 设置请求方式  
	        connection.setRequestProperty("User-Agent", "SmsClinet-SDK");
	        connection.setRequestProperty("Accept", "application/json");// 设置接收数据的格式  
	        connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); // 设置发送数据的格式  
	        connection.connect();
	        OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream(), "UTF-8");
	        String body ="";//request请求内容
	        //加密之前签名
	        String sign = SignUtils.sign(json);//签名值
	        //判断是否加密,若加密要明文传输appid
	        if( this.isEncrypt ){
	        	String text = AESUtils.parseByte2HexStr(AESUtils.encrypt(body,secretKey));
	        	body = "text="+ text +"&isEncrypt=true&sign="+sign+"&appId="+appId;
	        }else {
	        	body = "text="+ body +"&isEncrypt=false&sign="+sign;
	        }
	        out.append(body);
	        out.flush();  
	        out.close();
	        InputStream inputStream = connection.getInputStream();  
	        //对应的字符编码转换  
	        Reader reader = new InputStreamReader(inputStream, "UTF-8");  
	        BufferedReader bufferedReader = new BufferedReader(reader);  
	        String str = null;
	        StringBuffer sb = new StringBuffer();  
	        while ((str = bufferedReader.readLine()) != null) {  
	            sb.append(str);  
	        }
	        reader.close();
	        String resultBody = sb.toString();
	        Integer code = connection.getResponseCode();
	        if ( code == 200) {
	            // 对结果进行解析
	            RestResult result = parseResult(resultBody);
	            logger.log(Level.FINE, "发送结果：" + resultBody);
	            if (result == null) {
	                throw new SendSmsException("意外的结果:" + resultBody);
	            } else if (result.getState() != 0) {
	                throw new SendSmsException("发送短信失败:" + result.getMessage());
	            }
	        } else {
	            logger.log(Level.INFO, "发送结果：" + resultBody);
	            throw new SendSmsException("发送短信失败(" + code + ")");
	        }
	        connection.disconnect();
    	} catch (IOException e) {
            throw new SendSmsException(e);
        }finally {
        	log.append("===================SmsClinet-end=============================");
        	System.out.println(log.toString());
		}
    }
    
    /**
     * 对结果进行解析
     * @param content
     * @return
     */
    public static RestResult parseResult(String content) {
        RestResult result = null;
        Matcher matcher = RESULT_PATTERN.matcher(content);
        if (matcher.find()) {
            result = new RestResult();
            result.setState(Integer.parseInt(matcher.group(1)));
            result.setMessage(matcher.group(2));
        }
        return result;
    }
    
	/** 随机生成6位纯数字的验证码 */
	public String createCode() {// 生成验证码
		int len = charset.length() - 1;
		String result = "";
		for (int i = 0; i < codelen; i++) {
			char[] arrs = charset.toCharArray();
			Random r = new Random();
			result += arrs[r.nextInt(len)];
		}
		return result;
	}
	
	public String getUrl() {
        return url;
    }
    public String getAppId() {
        return appId;
    }
    public String getSecretKey() {
        return secretKey;
    }
	public String getTemplateCode() {
		return templateCode;
	}
    public void setUrl(String url) {
		this.url = url;
	}
	public void setAppId(String appId) {
		this.appId = appId;
	}
	public void setSecretKey(String secretKey) {
		this.secretKey = secretKey;
	}
	public void setTemplateCode(String templateCode) {
		this.templateCode = templateCode;
	}
	public boolean isEncrypt() {
		return isEncrypt;
	}
	public void setEncrypt(boolean isEncrypt) {
		this.isEncrypt = isEncrypt;
	}
	public boolean isDebug() {
		return isDebug;
	}
	public void setDebug(boolean isDebug) {
		this.isDebug = isDebug;
	}

	/**
     * @desc 响应实体类
     * @author wjw
     * @time 2017年11月20日下午6:01:23
     */
    private static class RestResult {
        
        /** 发送状态 */
        private int state;
        /** 响应描述 */
        private String message;
        
        public int getState() {
            return state;
        }
        public void setState(int state) {
            this.state = state;
        }
        public String getMessage() {
            return message;
        }
        public void setMessage(String message) {
            this.message = message;
        }
        
        @Override
        public String toString() {
            return "RestResult [state=" + state + ", message=" + message + "]";
        }
        
    }
}
